using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Hermes.Framework.FileSystem;
using Hermes.Framework.FileSystem.Local;

namespace Hermes.Framework.FileSystem.Ftp
{
    public abstract class FtpFileSystemTemplate : INonTransactableFileSystem
    {
        protected LocalFileSystem localFileSystem;

        public static readonly int DEFAULT_FTP_PORT = 21;

        public FtpFileSystemTemplate()
        {
            this.localFileSystem = new LocalFileSystem();
        }

        public abstract void Connect(ConnectionInfo connectionInfo);

        public void CreateFile(string fileName)
        {
            int lastSlash = fileName.LastIndexOf('/');
            string localFileName = @"C:\" + fileName.Substring(lastSlash, fileName.Length - lastSlash);
            FileStream fs = File.Create(localFileName);
            fs.Close();
            this.Copy(localFileName, fileName);
            File.Delete(localFileName);
        }

        public void Copy(string from, string to)
        {
            if (FileSystemUtils.IsLocalFileSystem(from) && FileSystemUtils.IsFileTransferProtocol(to))
            {
                string fromFileName = FileSystemUtils.GetFileName(from);
                fromFileName = FileSystemUtils.GetRelativePath(fromFileName);

                Url url = new Url(to);
                ChangeRemoteDirectory(url.Directory);
                PutFile(fromFileName, url.File);
            }
            else if (FileSystemUtils.IsFileTransferProtocol(from) && FileSystemUtils.IsLocalFileSystem(to))
            {
                string toFileName = FileSystemUtils.GetFileName(to);
                toFileName = FileSystemUtils.GetRelativePath(toFileName);

                Url url = new Url(from);
                ChangeRemoteDirectory(url.Directory);
                GetFile(url.File, to);
            }
            else
            {
                throw new ApplicationException("The transfer is not a kind of FTP.");
            }
        }

        public void Rename(string from, string to)
        {
            if (from.StartsWith("file://") && to.StartsWith("file://"))
            {
                this.localFileSystem.Rename(from, to);
                return;
            }
            Url fromUrl = new Url(from);
            ChangeRemoteDirectory(fromUrl.Directory);

            Url toUrl = new Url(to);
            DoRename(from, to);
        }

        public void Delete(string fileName)
        {
            if (fileName.StartsWith("file://"))
            {
                this.localFileSystem.Delete(fileName);
                return;
            }
            Url url = new Url(fileName);
            ChangeRemoteDirectory(url.Directory);
            DoDelete(url.File);
        }

        public abstract void ChangeRemoteDirectory(string directoryName);

        public abstract void DoDelete(string fileName);

        public abstract bool IsExisted(string fileName);

        public abstract void DoDeleteDirectory(string directoryName);

        public abstract void DoCreateDirectory(string directoryName);

        public abstract int GetNumberOfItems(string directoryName);

        public abstract string GetItemName(string directoryName, int index);

        public abstract void GetFile(string from, string to);

        public abstract void PutFile(string from, string to);

        public abstract void DoRename(string from, string to);

        public abstract void DoRenameDirectory(string from, string to);

        public bool Exists(string fileName)
        {
            if (fileName.StartsWith("file://"))
            {
                return this.localFileSystem.Exists(fileName);
            }

            Url url = new Url(fileName);
            ChangeRemoteDirectory(url.Directory);
            return IsExisted(url.File);
        }

        public bool IsDirectory(string directoryName)
        {
            if (directoryName.StartsWith("file://"))
            {
                return this.localFileSystem.IsDirectory(directoryName);
            }
            return false;
        }

        public void CreateDirectory(string directoryName)
        {
            if (directoryName.StartsWith("file://"))
            {
                this.localFileSystem.CreateDirectory(directoryName);
            }
            else
            {
                DoCreateDirectory(directoryName);
            }
        }

        public void RemoveDirectory(string directoryName)
        {
            if (directoryName.StartsWith("file://"))
            {
                this.localFileSystem.RemoveDirectory(directoryName);
            }
            else
            {
                Url url = new Url(directoryName);
                //ChangeRemoteDirectory(url.Directory);
                DoDeleteDirectory(url.Directory);
            }
        }

        public int GetItemCount(string directoryName)
        {
            if (directoryName.StartsWith("file://"))
            {
                return this.localFileSystem.GetItemCount(directoryName);
            }

            Url url = new Url(directoryName);
            ChangeRemoteDirectory(url.Directory);
            return GetNumberOfItems(url.Directory);
        }

        public string GetItem(string directoryName, int index)
        {
            if (directoryName.StartsWith("file://"))
            {
                return this.localFileSystem.GetItem(directoryName, index);
            }

            Url url = new Url(directoryName);
            ChangeRemoteDirectory(url.Directory);
            return GetItemName(url.Directory, index);
        }

        public void RenameDirectory(string from, string to)
        {
            this.Rename(from, to);
        }

        public abstract void Dispose();
    }
}
